package com.util;

import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.Security;
import java.util.Arrays;

import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

/**
 *
 * @author ngh AES128 算法
 *
 *         CBC 模式
 *
 *         PKCS7Padding 填充模式
 *
 *         CBC模式需要添加一个参数iv
 *
 *         介于java 不支持PKCS7Padding，只支持PKCS5Padding 但是PKCS7Padding 和 PKCS5Padding
 *         没有什么区别 要实现在java端用PKCS7Padding填充，需要用到bouncycastle组件来实现
 */
public class AES {
	// 算法名称
	static final String KEY_ALGORITHM = "AES";
	// 加解密算法/模式/填充方式
	static final String algorithmStr = "AES/CBC/PKCS7Padding";
	//
	private static Key key;
	private static Cipher cipher;
	static boolean isInited = false;

//	byte[] iv = { 0x30, 0x31, 0x30, 0x32, 0x30, 0x33, 0x30, 0x34, 0x30, 0x35, 0x30, 0x36, 0x30, 0x37, 0x30, 0x38 };
	static byte[] iv = "ca3762af61e59520".getBytes();
	public static void init(byte[] keyBytes) {

		// 如果密钥不足16位，那么就补足. 这个if 中的内容很重要
		int base = 16;
		if (keyBytes.length % base != 0) {
			int groups = keyBytes.length / base + (keyBytes.length % base != 0 ? 1 : 0);
			byte[] temp = new byte[groups * base];
			Arrays.fill(temp, (byte) 0);
			System.arraycopy(keyBytes, 0, temp, 0, keyBytes.length);
			keyBytes = temp;
		}
		// 初始化
		Security.addProvider(new BouncyCastleProvider());
		// 转化成JAVA的密钥格式
		key = new SecretKeySpec(keyBytes, KEY_ALGORITHM);
		try {
			// 初始化cipher
			cipher = Cipher.getInstance(algorithmStr, "BC");
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (NoSuchPaddingException e) {
			e.printStackTrace();
		} catch (NoSuchProviderException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 加密方法
	 *
	 * @param content
	 *            要加密的字符串
	 * @param keyBytes
	 *            加密密钥
	 * @return
	 */
	public static byte[] encrypt(byte[] content, byte[] keyBytes) {
		byte[] encryptedText = null;
		init(keyBytes);
		System.out.println("IV：" + new String(iv));
		try {
			cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv));
			encryptedText = cipher.doFinal(content);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return encryptedText;
	}

	/**
	 * 解密方法
	 *
	 * @param encryptedData
	 *            要解密的字符串
	 * @param keyBytes
	 *            解密密钥
	 * @return
	 */
	public static byte[] decrypt(byte[] encryptedData, byte[] keyBytes) {
		byte[] encryptedText = null;
		init(keyBytes);
		try {
			cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
			encryptedText = cipher.doFinal(encryptedData);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return encryptedText;
	}

	public static void main(String[] args) throws DecoderException {
		// 加解密 密钥
		byte[] keybytes = "d37a3a629281f797".getBytes();
		String content = "{\"code\":\"023Evl001x13rW1wcMZZ0UxB001Evl02\",\"appid\":\"wxc81db7a6571c4bec\",\"accNo\":\"\",\"provinceId\":\"\",\"parentId\":\"\",\"memberRegisterChannel\":\"\",\"latitude\":22.55329,\"longitude\":113.88308,\"accessToken\":\"\",\"uuid\":\" 7cc16529-f4f3-4a3e-8213-a9419259d811\",\"version\":\"iOS 10.0.1\",\"os\":\"devtools\"}";
		// 加密字符串
		System.out.println("加密前的：" + content);
		System.out.println("加密密钥：" + new String(keybytes));
		// 加密方法
		byte[] enc = AES.encrypt(content.getBytes(), keybytes);
		System.out.println("加密后的内容：" + new String(new Hex().encode(enc)));
		// 解密方法
		byte[] dec = AES.decrypt(enc, keybytes);
		System.out.println("解密后的内容：" + new String(dec));
//		System.out.println(decryptString("197adcd8562f114a6f8fbd381761737bab5fee81ebb20cd58c25e9d8ff6d4bc23858a1aa58b7485b4a3058a9a9c1f6db750f4a3d3f40976d2543ec7e35a31e0fceeea5b8741777de10a2b6638641c6b48be13a810387e519a9de20d5fd9d6ffc6c2ad7bd4ed0eb6d477e57bf5b8caf4f9ae35dfdeda65c303b183f1392139f0c525c92b51efa5e15aed09346abd2ccdd7d3f4ff35762a42e5f96b479b5517b2b77ec225b8a26c153091bc3ea749ceba7", keybytes));
		System.out.println(decryptString("1D0DFC1C0B21E15A91C61E4FD6E51C2B421578A29086A88424DFF2C6E1AA32B9367B566D90810D164DC134A51375F885641BC27522D0C3B06EC159FE50E8E0AC39B9E54A3300A58E62EA1B5A6A8B0F6B736C91FC88AC77D8F6AB600B82F15DDAC76A415F16FF9EF5D0CAFB080D2BBDE25622F0EA227FF1791F9D0B34740F73FA8B9D7140082F74C62ED83429CD541DBE945193D880190B7DDE7ECC6D666110437880D84032147873823BB2E508D13857EF078C0748AA6D5AEB9AC10DCBECADAFC1261C8A4219E88167F98F03FA89A25F6AEB5E70B8A29F8BD1B268C23AD8BB9F3E3F24065422882E0D42D0646B52FF417A85A7D4A2AB62A2B7385352143F9CA93966B8C1D684A7C18308FA448F98841AADA587AE6FEE0D95300E39776C78DDC0", keybytes));
		System.out.println(decryptString("6af4c9f04f106e836302d70a6dfcd18e031521a092c84e018c8f0170a3aeef8b7f882e4a2de90263727a323f0496586a17053b443ba5e52167b35151a1e6fd013330a0c9d106d4744638fe9641cdbf5a26285cb62e375e272ee6071035dca1ea22ea66f7704c2d8e32c9070b44bbc6a12211737e584560b5f454506ae4528f9d648bc8a3b8fde02f97ba76a5ce286a406ac2db305cc79b83b733ee06f5f224fe59ad2a9133c6bf7b46fef5acbdad4842", keybytes));
		
	}

	private static String decryptString(String content, byte[] keybytes) throws DecoderException {
		byte[] enc = Hex.decodeHex(content.toCharArray());
		byte[] dec = AES.decrypt(enc, keybytes);
		return new String(dec);
	}
	
}
